/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.travelFinder.service;

import com.travelFinder.domain.Place;
import java.util.*;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.PropertyContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 *
 * @author szwl
 */
@Service
public class JSONStructureBuilder {

	protected final static Logger logger = LoggerFactory.getLogger(JSONStructureBuilder.class);
	
	public Map<String, Object> validateArguments(Place start, Place end, Date starting_date) {
		Map<String, Object> root = new HashMap<String, Object>(2);
		
		if(start==null && end==null ){
			root.put("connections", "");
			root.put("error", "Stacje nie istnieją w bazie danych.");
			root.put("code",1);
		}else if(start==null){
			root.put("connections", "");
			root.put("error", "Stacja początkowa nie istnieje w bazie danych.");
			root.put("code",1);
		}else if(end == null){
			root.put("connections", "");
			root.put("error", "Stacja końcowa nie istnieje w bazie danych.");
			root.put("code",1);
		}else{
			root.put("code",0);
		}
		

		return root;
	}

	public Map<String, Object> buildFromPaths(Iterable<Path> paths, Date starting_date) {
		Map<String, Object> root = new HashMap<String, Object>(2);
		List<List<Map<String, Object>>> connections = new LinkedList<List<Map<String, Object>>>();

		if (paths == null) {
			root.put("connections", "");
			root.put("error", "Nie znaleziono połączeń.");
		} else {
			for (Path path : paths) {
				connections.add(buildFromPath(path, starting_date));
			}

			root.put("connections", connections);
			root.put("error", "");

		}

		return root;
	}

	private List<Map<String, Object>> buildFromPath(Path path, Date starting_date) {
		List<Map<String, Object>> connection = new LinkedList();
		List<String> stops = new LinkedList<String>();
		Map<String, Object> modelMap = new HashMap<String, Object>();

		PropertyContainer currentPlace;
		PropertyContainer currentConnection = null;


		String lastConnId = null;
		String start = null;

                int DAY_IN_MSECS = 86400000;
                long endDate = 0;
                Date startDate = null;
                
		for (Iterator<PropertyContainer> i = path.iterator();;) {
			//iterator zaczyna od place i potem na zmiane connection - place zwraca
			currentPlace = i.next();

			//jesli spelnione - sciezka miala jeden element tylko
			if (!i.hasNext()) {
				modelMap.put("destination", currentPlace.getProperty("name"));
				modelMap.put("stops", stops);
                                    long currTime = startDate.getTime()%DAY_IN_MSECS;
                                    if(endDate < currTime)
                                    {
                                        endDate += DAY_IN_MSECS;
                                    }
                                    modelMap.put("ending_date", new Date(startDate.getTime() - currTime + endDate));
				connection.add(modelMap);
				break;
			}

			if (start == null) {
				start = currentPlace.getProperty("name").toString();
			}

                        
			currentConnection = i.next();


			//dla pierwszego noda tylko
			if (lastConnId == null) {

				modelMap = initModelMap(currentPlace, currentConnection);
                                
                            //wyznaczanie daty
                            startDate = (Date) starting_date.clone();
                            long currTime = startDate.getTime()%DAY_IN_MSECS;
                            long connTime = Integer.parseInt(currentConnection.getProperty("startTime").toString()) * 1000 * 60;
                            if (currTime >= connTime) {
                                startDate = new Date(startDate.getTime() - currTime + DAY_IN_MSECS);
                            } else {
                                startDate = new Date(startDate.getTime() - currTime);
                            }
                            if (new Date(Long.parseLong(currentConnection.getProperty("startDate").toString())).after(startDate)) {
                                startDate = new Date(Long.parseLong(currentConnection.getProperty("startDate").toString()));
                            }
                            startDate = new Date(startDate.getTime() + connTime);
                            int duration = Integer.parseInt(currentConnection.getProperty("duration").toString()) * 60;
                            endDate = connTime + duration * 1000;
                            modelMap.put("starting_date", startDate);
                                
			} //bez przesiadki oraz nie startowy punkt - dopisz do przystankow
			else if (lastConnId.equals(currentConnection.getProperty("connectionId").toString()) && !start.equals(currentPlace.getProperty("name"))) {
				stops.add(currentPlace.getProperty("name").toString());
                                
                                long connTime = Integer.parseInt(currentConnection.getProperty("startTime").toString()) * 1000 * 60;
                                int duration = Integer.parseInt(currentConnection.getProperty("duration").toString()) * 60;
                                endDate = connTime + duration * 1000;
			} //przesiadka
			else {
				modelMap.put("destination", currentPlace.getProperty("name"));
				modelMap.put("stops", stops);
                                
                                    long currTime = startDate.getTime()%DAY_IN_MSECS;
                                    if(endDate < currTime)
                                    {
                                        endDate += DAY_IN_MSECS;
                                    }
                                    startDate = new Date(startDate.getTime() - currTime + endDate);
                                    modelMap.put("ending_date", startDate);
				
                                connection.add(modelMap);
				modelMap = initModelMap(currentPlace, currentConnection);
                                
                                    long connTime = Integer.parseInt(currentConnection.getProperty("startTime").toString()) * 1000 * 60;
                                    currTime = startDate.getTime()%DAY_IN_MSECS;
                                    if(currTime > connTime)
                                    {
                                        currTime -= DAY_IN_MSECS;
                                    }
                                    startDate = new Date(startDate.getTime() - currTime + connTime);
                                    modelMap.put("starting_date", startDate);
                                    int duration = Integer.parseInt(currentConnection.getProperty("duration").toString()) * 60;
                                    endDate = connTime + duration * 1000;
				
                                stops = new LinkedList();
				start = currentPlace.getProperty("name").toString();
			}



			lastConnId = currentConnection.getProperty("connectionId").toString();
		}

		return connection;

	}

	private Map<String, Object> initModelMap(PropertyContainer place, PropertyContainer connection) {
		Map<String, Object> modelMap = new HashMap<String, Object>();
		//jak connection null to znaczy ze tylko jeden node byl
		if (connection == null) {
			modelMap.put("carrier", "Weź taxi");
			modelMap.put("model", "not implemented in db");
			modelMap.put("starting_point", place.getProperty("name").toString());
			modelMap.put("starting_date", "A kiedy chcesz");
			modelMap.put("ending_date", "Zależy od korków");
			modelMap.put("notes", "dodatkowe informacje");
			modelMap.put("stops", new LinkedList());
			modelMap.put("destination", place.getProperty("name").toString());
		} else {
			modelMap.put("carrier", connection.getProperty("company").toString());
			modelMap.put("model", connection.getProperty("connectionId").toString());
			modelMap.put("starting_point", place.getProperty("name").toString());
			//modelMap.put("starting_date", connection.getProperty("startDate").toString());
			//modelMap.put("ending_date", connection.getProperty("endDate").toString());
			modelMap.put("notes", "dodatkowe informacje");
		}

		return modelMap;
	}
}
